//file: include/kernel/exeception/exception.h
//autor:jiangxinpeng
//time:2021.1.17
//copyright:(C) 2020-2050 by jiangxinpeng,All right are reserved.

#ifndef OS_EXCEPTION_H
#define OS_EXCEPTION_H

#include <os/spinlock.h>
#include <os/waitqueue.h>
#include <lib/list.h>
#include <arch/interrupt.h>
#include <lib/type.h>

//exception code
enum exc_code
{
    EXC_CODE_UNKNOW = 0,
    EXC_CODE_USER,
    EXC_CODE_INT,
    EXC_CODE_ILL,      //invalid instruction
    EXC_CODE_TRAP,     //tracer/breakpoint trap
    EXC_CODE_ABORT,    //stoping process
    EXC_CODE_BUS,      //mem apccess error
    EXC_CODE_SEGV,     //invaild mem reference
    EXC_CODE_FPE,      //fpu error
    EXC_CODE_FINALHIT, //final hlt
    EXC_CODE_PIPE,     //pipe close
    EXC_CODE_STKFLT,   //coprocess stack fault
    EXC_CODE_ALRM,     //real timer expired
    EXC_CODE_TERM,     //end proccess
    EXC_CODE_CHLD,     //abort or stopping sub process
    EXC_CODE_CONT,     //if stopping just continue
    EXC_CODE_STOP,     //assert stopping
    EXC_CODE_TTIN,     //terminal in
    EXC_CODE_TTOU,     //terminal write
    EXC_CODE_SYS,      //invalid syscall
    EXC_CODE_DEVICE,   //device error
    EXC_CODE_MAX       //exc code max
};

//exception block
typedef struct
{
    list_t list;    //single task exception list
    uint32_t code;  //exception code
    uint32_t flags; //flags
    pid_t source;   //except source
} exception_t;

typedef void (*exception_handler_t)();

//exception manager
typedef struct
{
    list_t exception_list;                           //exception list
    list_t catch_list;                               //catch list
    uint32_t exception_num;                          //exception num
    uint32_t catch_num;                              //catch num
    int user_mode;                                   //exception happend in user mode
    wait_queue_t waitqueue;                          //need asleep queue
    spinlock_t manager_lock;                         //manager lock
    uint32_t exception_block[EXC_CODE_MAX / 32 + 1]; //exception block situation
    uint32_t exception_catch[EXC_CODE_MAX / 32 + 1]; //exception catch situation
    exception_handler_t handler[EXC_CODE_MAX];       //exception handler
} exception_manager_t;

//exception frame
typedef struct
{
    void *return_addr;       //return address
    uint32_t code;           //error code
    trap_frame_t trap_frame; //save before trap frame
    uint8_t return_code[8];  //return code
} exception_frame_t;

void ExceptionManagerExit(exception_manager_t *manager);
void ExceptionManagerInit(exception_manager_t *manager);

int ExceptionCanCatch(exception_manager_t *manager, uint32_t code);
int ExceptionWasBlock(exception_manager_t *manager, uint32_t code);

void ExcepetionEnBlock(exception_manager_t *manager, uint32_t code);
void ExceptionEnCatch(uint32_t code, exception_handler_t handler, exception_manager_t *manager);
void ExceptionUnCatch(uint32_t code, exception_manager_t *manager);
void ExceptionUnBlock(exception_manager_t *manager, uint32_t code);
int ExceptionCopy(exception_manager_t *dest, exception_manager_t *src);
exception_t *ExceptionCreate(uint32_t code, pid_t source, uint32_t flags);

int SysExceptionSend(pid_t pid, uint32_t code);
int SysExceptionBlock(uint32_t code, uint32_t status);
int SysExceptionCatch(uint32_t code, exception_handler_t handler);
int SysExceptionReturn(uint32_t ebx,uint32_t ecx,uint32_t edx,uint32_t esi,uint32_t edi, trap_frame_t *frame);
void *SysExceptionHandler(uint32_t code);
int SysExceptionMask(uint32_t *mask);

void ExceptionDelKernel(exception_manager_t *manager, exception_t *exc);
void ExceptionAddKernel(exception_manager_t *manager, exception_t *exc);
void ExceptionAddCatch(exception_manager_t *manager, exception_t *exception);
void ExceptionDelCatch(exception_manager_t *manager, exception_t *exception);

int ExceptionSend(pid_t pid, uint32_t code);
int ExceptionSendGroup(pid_t pgid, uint32_t code);
int ExceptionForceSelf(uint32_t code);
int ExceptionForce(pid_t pid, uint32_t code);
int ExceptionReturn(trap_frame_t *frame);
void ExceptionFrameBuild(uint32_t code, exception_handler_t handler, trap_frame_t *frame);
int ExceptionDisPatch(exception_manager_t *manager, exception_t *exc);
int ExceptionRaise(uint32_t code);

void ExceptionCheck(trap_frame_t *frame);
int ExceptionCheckKernel(trap_frame_t *frame);
int ExceptionCheckUser(trap_frame_t *frame);
bool ExceptionCauseExit(exception_manager_t *manager);
bool ExceptionCauseExitWhenWait(exception_manager_t *manager);

#endif